//go:build !viper_yaml2
// +build !viper_yaml2

package server

import (
	"file-cleaner/internal/file_cleaner/clean_handler"
	"file-cleaner/internal/file_cleaner/cleaner"
	"file-cleaner/internal/file_cleaner/pool"
	"file-cleaner/internal/file_cleaner/querier"
	"file-cleaner/internal/file_cleaner/query_handler"
	"file-cleaner/internal/file_cleaner/queue"
	"file-cleaner/internal/file_cleaner/report"
	"github.com/marmotedu/errors"
	"time"
)

type RuntimeInfo struct {
	GoroutinePoolCap int
	GCCycle          time.Duration
}

type QueryHandlerBuilder struct {
	Builder    query_handler.HandlerBuilder
	TimeAfter  time.Time
	TimeBefore time.Time
}

type QueryInfo struct {
	BaseDir           string
	Excludes          []string
	QueryHandlerChain []QueryHandlerBuilder
	IsCascade         bool
}

type CleanInfo struct {
	BeforeHandlerChain          []clean_handler.HandlerBuilder
	MainHandlerChain            []clean_handler.HandlerBuilder
	TroubleshootingHandlerChain []clean_handler.HandlerBuilder
	FinishHandlerChain          []clean_handler.HandlerBuilder
}

type ReportInfo struct {
	ReporterBuilder report.ReporterBuilder
}

type Config struct {
	Runtime *RuntimeInfo
	Query   *QueryInfo
	Clean   *CleanInfo
	Report  *ReportInfo
}

func NewConfig() *Config {
	return &Config{
		Runtime: new(RuntimeInfo),
		Query:   new(QueryInfo),
		Clean:   new(CleanInfo),
		Report:  new(ReportInfo),
	}
}

type CompletedConfig struct {
	*Config
}

func (c *Config) Complete() CompletedConfig {
	return CompletedConfig{c}
}

func (c CompletedConfig) NewServer() (*Server, error) {
	// 生成清理任务信息采集者
	collector, cache := clean_handler.GenCleanTaskInfoCollectorAndCache()

	// build api
	qpool, err := pool.NewPool(c.Runtime.GoroutinePoolCap)
	if err != nil {
		return nil, err
	}
	cpool, err := pool.NewPool(c.Runtime.GoroutinePoolCap)
	if err != nil {
		return nil, err
	}
	fq, qq, cq := queue.NewQueue(), queue.NewQueue(), queue.NewQueue()

	qhc := query_handler.NewQueryHandlerChain(fq, qq, qpool)
	chc := clean_handler.NewCleanHandlerChain(cq, cpool)

	queryHandlers := make([]query_handler.QueryHandler, 0)
	for _, qhb := range c.Query.QueryHandlerChain {
		qh, err := qhb.Builder.Build()
		if err != nil {
			if errors.Is(err, query_handler.BuildNeedWithTimeRange) {
				qh, err = qhb.Builder.BuildWithTimeRange(qhb.TimeAfter, qhb.TimeBefore)
				if err != nil {
					return nil, err
				}
			} else {
				return nil, err
			}
		}
		queryHandlers = append(queryHandlers, qh)
	}
	if queryHandlers != nil && len(queryHandlers) > 0 {
		err = qhc.RegisterHandler(queryHandlers...)
		if err != nil {
			return nil, err
		}
	}

	beforeCleanHandlers, err := buildCleanHandlers(c.Clean.BeforeHandlerChain, collector)
	if err != nil {
		return nil, err
	}

	if beforeCleanHandlers != nil && len(beforeCleanHandlers) > 0 {
		err = chc.RegisterBeforeHandler(beforeCleanHandlers...)
		if err != nil {
			return nil, err
		}
	}

	mainCleanHandlers, err := buildCleanHandlers(c.Clean.MainHandlerChain, collector)
	if err != nil {
		return nil, err
	}
	if mainCleanHandlers != nil && len(mainCleanHandlers) > 0 {
		err = chc.RegisterMainHandler(mainCleanHandlers...)
		if err != nil {
			return nil, err
		}
	}

	troubleshootingCleanHandlers, err := buildCleanHandlers(c.Clean.TroubleshootingHandlerChain, collector)
	if err != nil {
		return nil, err
	}
	if troubleshootingCleanHandlers != nil && len(troubleshootingCleanHandlers) > 0 {
		err = chc.RegisterTroubleshootingHandler(troubleshootingCleanHandlers...)
		if err != nil {
			return nil, err
		}
	}

	finishCleanHandlers, err := buildCleanHandlers(c.Clean.FinishHandlerChain, collector)
	if err != nil {
		return nil, err
	}
	if finishCleanHandlers != nil && len(finishCleanHandlers) > 0 {
		err = chc.RegisterFinishHandler(finishCleanHandlers...)
		if err != nil {
			return nil, err
		}
	}

	api := newFileCleanerApi(fq, qq, cq, qpool, cpool, querier.NewFileQuerier(c.Runtime.GoroutinePoolCap, fq), qhc, chc, cleaner.NewFileCleaner(qq, cq))

	// build reporter
	reporter, err := c.Report.ReporterBuilder.Build()
	if err != nil {
		return nil, err
	}

	return &Server{
		FileCleanerApi: api,
		Reporter:       reporter,
		TaskInfoCache:  cache,
		gcCycle:        c.Runtime.GCCycle,
		queryBaseDir:   c.Query.BaseDir,
		queryExcludes:  c.Query.Excludes,
		isCascadeQuery: c.Query.IsCascade,
	}, nil
}

func buildCleanHandlers(builders []clean_handler.HandlerBuilder, collector *clean_handler.CleanTaskInfoCollector) (cleanHandlers []clean_handler.CleanHandler, err error) {
	for _, builder := range builders {
		handler, err := builder.Build()
		if err != nil {
			if errors.Is(err, clean_handler.NeedInputCleanTaskInfoCollector) {
				handler, err = builder.BuildWithCollector(collector)
				if err != nil {
					return nil, err
				}
			} else {
				return nil, err
			}
		}

		cleanHandlers = append(cleanHandlers, handler)
	}
	return
}
